(ns tala.info
  (:use tala.db)
  (:use tala.util)
  (:use tala.rdf)
  (:use ring.util.response)
  (:use hiccup.core)
  (:import org.mulgara.mrg.vocab.FOAF))

;;; The output of the various information functions below is currently
;;; rather poor. This should be fixed in the fullness of time, but the
;;; overall structure is OK.

;; Query strings
(def search-for-tag1
  ;; Search for single-object tags
  "select
     lod_services.ident as svc, lod_tables.ident as tbl, lod_columns.ident as col, lod_rows.ident as row,
     lod_accounts.name as user
   from
     lod_services, lod_tables, lod_columns, lod_rows, lod_rowtags, lod_tags, lod_accounts
   where
         lod_services.ident = lod_tables.parent
     and lod_tables.ident = lod_columns.parent
     and lod_columns.ident = lod_rows.parent
     and lod_rows.ident = lod_rowtags.taprow
     and lod_rowtags.tag = lod_tags.ident
     and lod_tags.owner = lod_accounts.ident
     and lod_tags.name = ? --'10red'
   ;")
(def search-for-tag2
  ;; Search for two-object tags
  "select
     s1.ident as svc1, t1.ident as tbl1, c1.ident as col1, r1.ident as row1,
     s2.ident as svc2, t2.ident as tbl2, c2.ident as col2, r2.ident as row2
   from
     lod_services s1, lod_tables t1, lod_columns c1, lod_rows r1,
     lod_services s2, lod_tables t2, lod_columns c2, lod_rows r2,
     lod_joins, lod_jointags, lod_tags
   where
     s1.ident = t1.parent and t1.ident = c1.parent and c1.ident = r1.parent
       and r1.ident = lod_joins.one
     and
     s2.ident = t2.parent and t2.ident = c2.parent and c2.ident = r2.parent
       and r2.ident = lod_joins.two
     and lod_jointags.tapjoin = lod_joins.ident
     and lod_jointags.tag = lod_tags.ident
     and lod_tags.name = ?
     ;")
;; (def search-for-tag-by-user
;;   "select "
;;   "select tapservices.name as svc, taptables.name as tbl, results.oid as oid
;;    from accounts, tapservices, taptables, queries, results, querytags, tags
;;    where tags.name = ?
;;       and querytags.tag = tags.ident
;;       and querytags.owner = accounts.ident
;;       and accounts.email = ?
;;       and results.query = querytags.query
;;       and queries.ident = querytags.query
;;       and taptables.ident = queries.taptable
;;       and tapservices.ident = taptables.tapservice
;;       and accounts.ident = querytags.owner
;;       ;")

;; SEARCH-FOR-TAGGED-OBJECTS : db string string -> response
;; Search for objects tagged with TAG, and respond with content in the
;; requested MIME type.
(defn search-for-tagged-objects [db tag required-mime-type]
  (respond-html (str "Things tagged with " tag)
                [:p "There are various things tagged with " [:strong tag]]
                [:ul
                 (make-query db [search-for-tag1 tag]
                             (fn [seq]
                               (if seq
                                 (map (fn [t]
                                        [:li (str (:svc t) "/" (:tbl t) "/" (:col t) "/" (:row t)
                                                  " by " (:user t))])
                                      ;; we have to force the sequence here, rather than
                                      ;; let hiccup do it, because all of the DB stream
                                      ;; lookups must be complete before we leave the
                                      ;; scope of make-query
                                      (into [] seq))
                                 [:li "Nothing tagged with " tag])))]))

;; SEARCH-FOR-TAGGED-OBJECTS-BY-USER : db string string string -> response
;; Search for objects tagged with TAG by user USER, and respond with content in the
;; requested MIME type.  FIXME: in fact, the MIME type argument is
;; currently ignored, and the only response is HTML.
;; (defn search-for-tagged-objects-by-user [db tag user required-mime-type]
;;   (respond-html (str "Things tagged with " tag " by user " user)
;;                 [:p "There are various things tagged by user " user " with tag " tag]
;;                 [:ul
;;                  (make-query db [search-for-tag-by-user tag user]
;;                              (fn [seq]
;;                                (map (fn [t]
;;                                       [:li (str (:svc t) "/" (:tbl t) "/" (:oid t))])
;;                                     (into [] seq))))]))

;; (defmacro inputstream-from-thread [body]
;;   "Run the body in a thread, and return an InputStream connected to it.
;; Anything the body writes to *out* will be available on the input
;; stream.  The body should not close *out*."
;;   `(let [pis# (java.io.PipedInputStream.)]
;;      (let [pos# (java.io.PipedOutputStream. pis#)]
;;        (.start
;;         (Thread.
;;          (fn []
;;            (binding [*out* pos#]
;;                      ~body)
;;            (.close pos#))))
;;        pis#)))

;; (defn- describe-user-rdf [db user-email turtle?]
;;   "Describe the user with the given email address.  If TURTLE? is
;; true, output Turtle, otherwise RDF/XML"
;;   (let [name (make-query db ["select name from accounts where email = ?" user-email]
;;                          (fn [seq] (:name (first seq))))
;;         u (java.net.URI. (str "/id/u/" user-email))]
;;     (let [graph (make-simple-graph [[u :a FOAF/PERSON]
;;                                     [u
;;                                      (.resolve (.getURI FOAF/BASE_URI) "mbox")
;;                                      (java.net.URI. (str "mailto:" user-email))]
;;                                     [u FOAF/NAME name]])]
;;       (-> (response (inputstream-from-thread
;;                      (if turtle?
;;                        (.exportN3 graph *out*)
;;                        (.exportXML graph *out*))))
;;           (content-type (if turtle? "text/turtle" "application/rdf+xml"))))))


;; ;; DESCRIBE-USER-HTML : db string -> response
;; ;; This is possibly a bit of an anomaly.  This is to support the /data/u tree,
;; ;; which should possibly be only RDF or, say, JSON, but this supports
;; ;; doing that in HTML.
;; (defn- describe-user-html [db user-email]
;;   (respond-html (str "Description of " user-email)
;;                 [:p "The person with email address " user-email " is "
;;                  (make-query db ["select name from accounts where email = ?" user-email]
;;                              (fn [seq] (:name (first seq))))]))

;; ;; DESCRIBE-USER : db string string -> response
;; (defn describe-user [db user-email accept-header]
;;   "Describe the given user, indexed by the email address, using the
;; MIME type implied by the full ACCEPT-HEADER."
;;   (loop [s (parse-accept-header accept-header)]
;;     (if (not s)
;;       (status (response "No acceptable response for accept header") 406)
;;       (case (first s)
;;         "text/html" (describe-user-html db user-email)
;;         ("text/turtle" "application/rdf+xml") (describe-user-rdf db user-email (= (first s) "text/turtle"))
;;         (recur (rest s))))))
